Step 0: Load packages and libraries

# check and install needed packages
There were 30 warnings (use warnings() to see them)
packages.used = c('tidytext', 'tidyverse', 'DT','wordcloud', 'wordcloud2',
                'htmlwidgets', 'plotly', 'RColorBrewer', 'sentimentr', 'stringr', 'tm')

packages.needed = setdiff(packages.used,
                          intersect(installed.packages()[,1],
                                    packages.used))
if(length(packages.needed)>0){
  install.packages(packages.needed, dependencies = TRUE)
}

# load packages
library(stringr)
library(tidytext)
library(tidyverse)
library(DT)
library(htmlwidgets)
library(plotly)
library(RColorBrewer)
library(sentimentr)
library(wordcloud)
library(wordcloud2)
library(tm)
source('../lib/functions.R')

#source(): if any lib needs to be sourced

This notebook was prepared with the following environmental settings:

print(R.version)
               _                           
platform       x86_64-apple-darwin17.0     
arch           x86_64                      
os             darwin17.0                  
system         x86_64, darwin17.0          
status                                     
major          4                           
minor          0.3                         
year           2020                        
month          10                          
day            10                          
svn rev        79318                       
language       R                           
version.string R version 4.0.3 (2020-10-10)
nickname       Bunny-Wunnies Freak Out     
There were 18 warnings (use warnings() to see them)

Step1: Read in the data from Kaggle: History of Philosophy

# read csv
data <- read_csv("../data/philosophy_data.csv")

head(data)

This is how the data looks like. Each row represents a sentence in the title; thus the number of rows represent the number of sentences written.

Step2: Data Preprocessing

Sentences are already tokenized and the sentence length is already computed in the given data. However, we do need to count the number of tokens in each sentence and add column n_tokens. The length function does not work here because the column is a character string, not a list.

# add number of tokens
new_data <- data %>%
  mutate(n_tokens = f.word_count(data$tokenized_txt))
# into a format that can be used to plot
tidy_df <- data %>% 
  dplyr::select(school, author, title) %>% 
  group_by(school, author) %>% 
  summarize(n_title = n_distinct(title),
            n_sent = n()) %>% 
  pivot_longer(cols = c("n_title", "n_sent"),
               names_to = "type",
               values_to = "count")

Step3: Exploratory Data Analysis

Number of Sentences

Before doing a text analysis, we want to know some information on the data. Here are some of the basic questions regarding:

I. Number of Titles and Sentences

Some people like writing lengthy writings, some like it succinct. Is there a preferene or tendency in the length of works depending on schools or titles?

  1. How many titles are there per school? Which school was the most active in publishing manuscripts?

How many titles and sentences per author? Which author has the most manuscripts?

  1. Distribution of number of sentences:
g2 <- tidy_df %>% filter(type== "n_sent") %>% 
  ggplot(aes(log10(count)))+
  geom_histogram(binwidth = .1, color= "black")+
  geom_density()+
  labs(title = "Number of sentences for each title",
       x= "log10(number of sentences)",
       y="Frequency")

g2

Doesn’t follow a known probability distribution. The global maximum(mode) is at around 10e4.1.

  1. How many sentences are there per school?

  1. Is there a correlation between the number of titles per school?

In other words, does more titles mean more sentences?

Through this side by side comparison, we see that the order is different when ordered according to title or number of sentences. Thus it can be inferred that more titles doesn’t necessarily mean more sentences. For better visualization/easy comparison:

Cleveland Dot Plot

This better shows that the more number of sentences does not automatically mean more titles. So, the works are not all of similar length, but some are shorter than others and some are longer than others.

  1. Number of sentences per title
g5 <- data %>% 
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
8: In readChar(file, size, TRUE) : truncating string with embedded nuls
  dplyr::select(school, author, title) %>% 
  ggplot()+
  geom_bar(aes(fct_infreq(title), fill=school))+
  scale_x_discrete(label = function(x) abbreviate(x, minlength = 7))+
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5))


ggplotly(g5)

If you hover over the graph you can isolate each school in the graph, like faceting. We can see that the length of the title doesn’t depend on each school. For example, schools that have multiple titles such as Analytic and german_idealism, there isn’t a distinct pattern in the length of titles by school.

  1. How about by author?

Since some authors have one title, for simplicity lets filter for authors with multiple works.

Again, hovering over the above plot, we can see that except for some authors, there is no clear pattern as to one would write short or long works. The horizontal line represents the mean of the number of sentences for all authors. By isolating the data for Descartes, we can see that both his work in the data shows very low number of sentences, whereas Heidegger’s works tend to be above average. Also, notice that Marx’s work is on both ends of the graph.

II. Sentence Length

  1. Length of sentences and tokens by schools, authors, titles

Total sentence length per title

Average sentence length per title

  1. Sentence length distribution
length_info <-summary(data$sentence_length)
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
8: In readChar(file, size, TRUE) : truncating string with embedded nuls
length_info
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   20.0    75.0   127.0   150.8   199.0  2649.0 
g.len <- new_data %>%
  dplyr::select(sentence_length) %>% 
  ggplot(aes(log10(sentence_length)))+
  geom_histogram(bins = 50, color="black")

g.len


token_info <- summary(new_data$n_tokens)
token_info
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00   13.00   22.00   25.69   34.00  398.00 
g.token <- new_data %>%
  dplyr::select(n_tokens) %>% 
  ggplot(aes(log10(n_tokens)))+
  geom_histogram(bins = 50, color= "black")

g.token

For which sentence has 0 tokens?

id <- which(new_data$n_tokens == 0)
new_data[id,c("sentence_str", "tokenized_txt")]


#filter out for rows that holds sentences without meaning
new_data <- new_data %>% 
  filter(n_tokens >0)

summary(new_data$n_tokens)
  1. Is there a correlation between number of sentences and number of words in a sentence by title? For example, did writings consist of many short sentences or few lengthy sentences?
corr_df <- title.per.school %>% 
  left_join(sent.len.df, by = c("school", "author", "title")) %>% 
  ungroup() %>% 
  dplyr::select(title, n_sent, n_tokens)

g.cor <- ggplot(corr_df)+
  geom_point(aes(log10(n_sent), log10(n_tokens)))

g.cor

The scatter plot seems to show some correlation between the 2 variables.

Statistically,

shapiro.test(corr_df$n_sent)
shapiro.test(corr_df$n_tokens)

We cannot compute the Pearson correlation between these 2 variables since it does not pass the Shapiro-Wilk test of normality. Instead, we compute the Kendall correlation that computes correlation by the “rank”.

result <- cor.test(corr_df$n_sent, corr_df$n_tokens, method = "kendall")
result

Although we cannot conclusively say that the longer the sentences, the longer the work as that would be too much of a stretch, we still can say that the works are not consisted of excessively much short sentences or less lengthy sentences.

Word Cloud

Many analysis has been done on how many distinct words were used by authors, or what words were mostly used by them. Instead, I tried to look at authors who had more than one title in this data to see if their use of words has changed over time. Let’s take a few authors from the list: Nietzsche, Hegel, and Kant

kant <- mlt_pub %>% filter(author == "Kant")
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
niet %>% select(title, original_publication_date) %>% 
There were 50 or more warnings (use warnings() to see the first 50)
  distinct(title, .keep_all=TRUE) %>% arrange(original_publication_date)
  
niet_txt1 <- niet %>% filter(original_publication_date==1886)
niet_txt2 <- niet %>% filter(original_publication_date==1887)
niet_txt3 <- niet %>% filter(original_publication_date==1888)

par(mfrow= c(1, 3))
create_wc(niet_txt1); create_wc(niet_txt2); create_wc(niet_txt3)

hegel %>% select(title, original_publication_date) %>% 
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
8: In readChar(file, size, TRUE) : truncating string with embedded nuls
  distinct(title, .keep_all=TRUE) %>% arrange(original_publication_date)
  
hegel_txt1 <- hegel %>% filter(original_publication_date==1807)
hegel_txt2 <- hegel %>% filter(original_publication_date==1817)
hegel_txt3 <- hegel %>% filter(original_publication_date==1820)

par(mfrow= c(1, 3))
create_wc(hegel_txt1); create_wc(hegel_txt2); create_wc(hegel_txt3)

kant %>% select(title, original_publication_date) %>% 
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
8: In readChar(file, size, TRUE) : truncating string with embedded nuls
9: In readChar(file, size, TRUE) : truncating string with embedded nuls
  distinct(title, .keep_all=TRUE) %>% arrange(original_publication_date)
  
kant_txt1 <- kant %>% filter(original_publication_date==1781)
kant_txt2 <- kant %>% filter(original_publication_date==1788)
kant_txt3 <- kant %>% filter(original_publication_date==1790)

par(mfrow= c(1, 3))
create_wc(kant_txt1); create_wc(kant_txt2); create_wc(kant_txt3)

Findings

We see both changes and nonchanges.

  1. For Nietzsche, for all three years the most used word is all similarly “one”, and “will”. However, we can see a shift in subject. Inthe early publication, he focuses more on man, morality, good, etc. However the last world cloud shows more of god, world, whole, people, and etc.
  2. For Hagel, he started out with words such as sprit, purem universal. Later, he has shifted to more od determinatoin, right, self, and consciousness rather than spiritual.
  3. For Kant, he constantly uses the words reason , law, judgment, empirical, etc. From his choice of words, we can see that his subjects are distinct from the previous 2 philosophers.
LS0tCnRpdGxlOiAnUHJvamVjdCAxOiBEYXRhIFN0b3J5IG9uIHRoZSBIaXN0b3J5IG9mIFBoaWxpc29waHknCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKCgojIyBTdGVwIDA6IExvYWQgcGFja2FnZXMgYW5kIGxpYnJhcmllcwoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgY2hlY2sgYW5kIGluc3RhbGwgbmVlZGVkIHBhY2thZ2VzCnBhY2thZ2VzLnVzZWQgPSBjKCd0aWR5dGV4dCcsICd0aWR5dmVyc2UnLCAnRFQnLCd3b3JkY2xvdWQnLCAnd29yZGNsb3VkMicsCiAgICAgICAgICAgICAgICAnaHRtbHdpZGdldHMnLCAncGxvdGx5JywgJ1JDb2xvckJyZXdlcicsICdzZW50aW1lbnRyJywgJ3N0cmluZ3InLCAndG0nKQoKcGFja2FnZXMubmVlZGVkID0gc2V0ZGlmZihwYWNrYWdlcy51c2VkLAogICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyc2VjdChpbnN0YWxsZWQucGFja2FnZXMoKVssMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2thZ2VzLnVzZWQpKQppZihsZW5ndGgocGFja2FnZXMubmVlZGVkKT4wKXsKICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2VzLm5lZWRlZCwgZGVwZW5kZW5jaWVzID0gVFJVRSkKfQoKIyBsb2FkIHBhY2thZ2VzCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoRFQpCmxpYnJhcnkoaHRtbHdpZGdldHMpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShzZW50aW1lbnRyKQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeSh3b3JkY2xvdWQyKQpsaWJyYXJ5KHRtKQpzb3VyY2UoJy4uL2xpYi9mdW5jdGlvbnMuUicpCmBgYAoKVGhpcyBub3RlYm9vayB3YXMgcHJlcGFyZWQgd2l0aCB0aGUgZm9sbG93aW5nIGVudmlyb25tZW50YWwgc2V0dGluZ3M6CmBgYHtyfQpwcmludChSLnZlcnNpb24pCmBgYAoKCiMjIFN0ZXAxOiBSZWFkIGluIHRoZSBkYXRhIGZyb20gW0thZ2dsZTogSGlzdG9yeSBvZiBQaGlsb3NvcGh5XShodHRwczovL3d3dy5rYWdnbGUuY29tL2tvdXJvc2hhbGl6YWRlaC9oaXN0b3J5LW9mLXBoaWxvc29waHkpCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KIyByZWFkIGNzdgpkYXRhIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3BoaWxvc29waHlfZGF0YS5jc3YiKQoKaGVhZChkYXRhKQpgYGAKVGhpcyBpcyBob3cgdGhlIGRhdGEgbG9va3MgbGlrZS4KRWFjaCByb3cgcmVwcmVzZW50cyBhIHNlbnRlbmNlIGluIHRoZSB0aXRsZTsgdGh1cyB0aGUgbnVtYmVyIG9mIHJvd3MgcmVwcmVzZW50IHRoZSBudW1iZXIgb2Ygc2VudGVuY2VzIHdyaXR0ZW4uCgoKIyMgU3RlcDI6IERhdGEgUHJlcHJvY2Vzc2luZwoKU2VudGVuY2VzIGFyZSBhbHJlYWR5IHRva2VuaXplZCBhbmQgdGhlIHNlbnRlbmNlIGxlbmd0aCBpcyBhbHJlYWR5IGNvbXB1dGVkIGluIHRoZSBnaXZlbiBkYXRhLgpIb3dldmVyLCB3ZSBkbyBuZWVkIHRvIGNvdW50IHRoZSBudW1iZXIgb2YgdG9rZW5zIGluIGVhY2ggc2VudGVuY2UgYW5kIGFkZCBjb2x1bW4gYG5fdG9rZW5zYC4KVGhlIGBsZW5ndGhgIGZ1bmN0aW9uIGRvZXMgbm90IHdvcmsgaGVyZSBiZWNhdXNlIHRoZSBjb2x1bW4gaXMgYSBjaGFyYWN0ZXIgc3RyaW5nLCBub3QgYSBsaXN0LgoKYGBge3J9CiMgYWRkIG51bWJlciBvZiB0b2tlbnMKbmV3X2RhdGEgPC0gZGF0YSAlPiUKICBtdXRhdGUobl90b2tlbnMgPSBmLndvcmRfY291bnQoZGF0YSR0b2tlbml6ZWRfdHh0KSkKYGBgCgpgYGB7cn0KIyBpbnRvIGEgZm9ybWF0IHRoYXQgY2FuIGJlIHVzZWQgdG8gcGxvdAp0aWR5X2RmIDwtIGRhdGEgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2Nob29sLCBhdXRob3IsIHRpdGxlKSAlPiUgCiAgZ3JvdXBfYnkoc2Nob29sLCBhdXRob3IpICU+JSAKICBzdW1tYXJpemUobl90aXRsZSA9IG5fZGlzdGluY3QodGl0bGUpLAogICAgICAgICAgICBuX3NlbnQgPSBuKCkpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoIm5fdGl0bGUiLCAibl9zZW50IiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiY291bnQiKQoKYGBgCgojIyBTdGVwMzogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcwojIyMgTnVtYmVyIG9mIFNlbnRlbmNlcwoKQmVmb3JlIGRvaW5nIGEgdGV4dCBhbmFseXNpcywgd2Ugd2FudCB0byBrbm93IHNvbWUgaW5mb3JtYXRpb24gb24gdGhlIGRhdGEuIEhlcmUgYXJlIHNvbWUgb2YgdGhlIGJhc2ljIHF1ZXN0aW9ucyByZWdhcmRpbmc6CgoKKipJLiBOdW1iZXIgb2YgVGl0bGVzIGFuZCBTZW50ZW5jZXMqKgoKU29tZSBwZW9wbGUgbGlrZSB3cml0aW5nIGxlbmd0aHkgd3JpdGluZ3MsIHNvbWUgbGlrZSBpdCBzdWNjaW5jdC4gSXMgdGhlcmUgYSBwcmVmZXJlbmUgb3IgdGVuZGVuY3kgaW4gdGhlIGxlbmd0aCBvZiB3b3JrcyBkZXBlbmRpbmcgb24gc2Nob29scyBvciB0aXRsZXM/CgoKMS4gSG93IG1hbnkgdGl0bGVzIGFyZSB0aGVyZSBwZXIgc2Nob29sPyBXaGljaCBzY2hvb2wgd2FzIHRoZSBtb3N0IGFjdGl2ZSBpbiBwdWJsaXNoaW5nIG1hbnVzY3JpcHRzPwoKICBIb3cgbWFueSB0aXRsZXMgYW5kIHNlbnRlbmNlcyBwZXIgYXV0aG9yPyBXaGljaCBhdXRob3IgaGFzIHRoZSBtb3N0IG1hbnVzY3JpcHRzPwogIApgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz0gRkFMU0V9CiMgZGF0YSBmcmFtZSB0aGF0IHNob3dzIHNjaG9vbCwgYXV0aG9yLCB0aXRsZSBhbmQgdGhlIG51LGJlciBvZiBzZW50ZW5jZXMgaW4gZWFjaCB0aXRsZQp0aXRsZS5wZXIuc2Nob29sIDwtIGRhdGEgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2Nob29sLCBhdXRob3IsdGl0bGUpICU+JSAKICBncm91cF9ieShzY2hvb2wsIGF1dGhvciwgdGl0bGUpJT4lIAogIHN1bW1hcmlzZShuX3NlbnQgPSBuKCkpCgp0aXRsZS5wZXIuYXV0aG9yIDwtIGRhdGEgJT4lIAogIGRwbHlyOjpzZWxlY3QoYXV0aG9yLCB0aXRsZSkgJT4lIAogIGdyb3VwX2J5KGF1dGhvciwgdGl0bGUpICU+JSAKICBzdW1tYXJpc2Uobl9zZW50ID0gbigpKQoKZGF0YXRhYmxlKHRpdGxlLnBlci5zY2hvb2wsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGg9NSkpCmRhdGF0YWJsZSh0aXRsZS5wZXIuYXV0aG9yLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoPTUpKQoKCiMgYXNzaWduIGVhY2ggc2Nob29sIHdpdGggYSBkaWZmZXJlbnQgY29sb3Igd2l0aCBjb25zaXN0ZW5jeQp0aXRsZS5wZXIuc2Nob29sJHNjaG9vbCA8LSBmYWN0b3IodGl0bGUucGVyLnNjaG9vbCRzY2hvb2wsIGxldmVscyA9IGModW5pcXVlKHRpdGxlLnBlci5zY2hvb2wkc2Nob29sKSkpCnNjaG9vbHMgPC0gYyhsZXZlbHModGl0bGUucGVyLnNjaG9vbCRzY2hvb2wpKQpnZXRQYWxldHRlIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgJ1NldDMnKSkKY29sb3JzIDwtIGdldFBhbGV0dGUoMTMpCm5hbWVzKGNvbG9ycyk8LSBzY2hvb2xzCgojIHBsb3QgZm9yIG51bWJlciBvZiB0aXRsZXMgcGVyIHBoaWxvc29waGljYWwgc2Nob29sICAKZzEgPC0gZ2dwbG90KHRpdGxlLnBlci5zY2hvb2wpKwogIGdlb21fYmFyKGFlcyh4PSBmY3RfaW5mcmVxKHNjaG9vbCksIGZpbGw9c2Nob29sKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gY29sb3JzKSsKICBsYWJzKHRpdGxlID0gJ051bWJlciBvZiB0aXRsZXMgcGVyIHBoaWxvc29waGljYWwgc2Nob29sJywKICAgICAgIHg9ICdTY2hvb2wnLAogICAgICAgeT0gJ1RpdGxlcyAoY291bnQpJykrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKICBjb29yZF9mbGlwKCkKCmcxCgpgYGAKCgoyLiBEaXN0cmlidXRpb24gb2YgbnVtYmVyIG9mIHNlbnRlbmNlczoKYGBge3J9CmcyIDwtIHRpZHlfZGYgJT4lIGZpbHRlcih0eXBlPT0gIm5fc2VudCIpICU+JSAKICBnZ3Bsb3QoYWVzKGxvZzEwKGNvdW50KSkpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEsIGNvbG9yPSAiYmxhY2siKSsKICBnZW9tX2RlbnNpdHkoKSsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBzZW50ZW5jZXMgZm9yIGVhY2ggdGl0bGUiLAogICAgICAgeD0gImxvZzEwKG51bWJlciBvZiBzZW50ZW5jZXMpIiwKICAgICAgIHk9IkZyZXF1ZW5jeSIpCgpnMgpgYGAKCkRvZXNuJ3QgZm9sbG93IGEga25vd24gcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLiBUaGUgZ2xvYmFsIG1heGltdW0obW9kZSkgaXMgYXQgYXJvdW5kIDEwZTQuMS4KCgozLiBIb3cgbWFueSBzZW50ZW5jZXMgYXJlIHRoZXJlIHBlciBzY2hvb2w/IAoKYGBge3J9CmczIDwtIGRhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChzY2hvb2wpICU+JSAKZ2dwbG90KCkrCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKGZjdF9pbmZyZXEoc2Nob29sKSwgZmlsbCA9IHNjaG9vbCksIHN0YXQ9ImNvdW50IikrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gY29sb3JzKSsKICBsYWJzKHRpdGxlPSAiTnVtYmVyIG9mIHNlbnRlbmNlcyBwZXIgcGhpbG9zb3BoaWNhbCBzY2hvb2wiLAogICAgICAgeD0gIlNjaG9vbCIsCiAgICAgICB5PSAiU2VudGVuY2VzIChjb3VudCkiKSsKICBjb29yZF9mbGlwKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmczCgpgYGAKCgozLiBJcyB0aGVyZSBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIG51bWJlciBvZiB0aXRsZXMgcGVyIHNjaG9vbD8KCkluIG90aGVyIHdvcmRzLCBkb2VzIG1vcmUgdGl0bGVzIG1lYW4gbW9yZSBzZW50ZW5jZXM/CgpgYGB7cn0KcGFyKG1mcm93PWMoMiwxKSkKZzE7IGczCgpgYGAKClRocm91Z2ggdGhpcyBzaWRlIGJ5IHNpZGUgY29tcGFyaXNvbiwgd2Ugc2VlIHRoYXQgdGhlIG9yZGVyIGlzIGRpZmZlcmVudCB3aGVuIG9yZGVyZWQgYWNjb3JkaW5nIHRvIHRpdGxlIG9yIG51bWJlciBvZiBzZW50ZW5jZXMuClRodXMgaXQgY2FuIGJlIGluZmVycmVkIHRoYXQgbW9yZSB0aXRsZXMgZG9lc24ndCBuZWNlc3NhcmlseSBtZWFuIG1vcmUgc2VudGVuY2VzLgpGb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24vZWFzeSBjb21wYXJpc29uOgoKKipDbGV2ZWxhbmQgRG90IFBsb3QqKgpgYGB7cn0KCmc0IDwtIHRpZHlfZGYgJT4lIAogIGdyb3VwX2J5KHNjaG9vbCwgdHlwZSkgJT4lIAogIHN1bW1hcmlzZShjb3VudD0gc3VtKGNvdW50KSkgJT4lIAogIGdncGxvdChhZXMobG9nMTAoY291bnQpLCBmY3RfcmVvcmRlcjIoc2Nob29sLCB0eXBlPT0ibl9zZW50IiwgbG9nMTAoY291bnQpLCAuZGVzYyA9IEZBTFNFKSwgY29sb3I9dHlwZSkpKwogIGdlb21fcG9pbnQoKSsKICBsYWJzKHRpdGxlPSAiQ29tcGFyaXNvbiBvZiBudW1iZXIgb2YgdGl0bGVzIGFuZCBzZW50ZW5jZXMgcGVyIHNjaG9vbCIsCiAgICAgICB4PSAibG9nMTAoY291bnQpIiwKICAgICAgIHk9ICJTY2hvb2wiKSsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iVHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIiMgb2Ygc2VudGVuY2VzIiwiIyBvZiB0aXRsZXMiKSwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YygicmVkIiwiYmx1ZSIpKQogIAoKZzQKYGBgClRoaXMgYmV0dGVyIHNob3dzIHRoYXQgdGhlIG1vcmUgbnVtYmVyIG9mIHNlbnRlbmNlcyBkb2VzIG5vdCBhdXRvbWF0aWNhbGx5IG1lYW4gbW9yZSB0aXRsZXMuClNvLCB0aGUgd29ya3MgYXJlIG5vdCBhbGwgb2Ygc2ltaWxhciBsZW5ndGgsIGJ1dCBzb21lIGFyZSBzaG9ydGVyIHRoYW4gb3RoZXJzIGFuZCBzb21lIGFyZSBsb25nZXIgdGhhbiBvdGhlcnMuCgoKNS4gTnVtYmVyIG9mIHNlbnRlbmNlcyBwZXIgdGl0bGUKCgpgYGB7ciwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OH0KZzUgPC0gZGF0YSAlPiUgCiAgZHBseXI6OnNlbGVjdChzY2hvb2wsIGF1dGhvciwgdGl0bGUpICU+JSAKICBnZ3Bsb3QoKSsKICBnZW9tX2JhcihhZXMoZmN0X2luZnJlcSh0aXRsZSksIGZpbGw9c2Nob29sKSkrCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIGFiYnJldmlhdGUoeCwgbWlubGVuZ3RoID0gNykpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdCA9IDEsIHZqdXN0PTAuNSkpKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIHNlbnRlbmNlcyBwZXIgdGl0bGUiLAogICAgICAgeD0gIlRpdGxlIChhYmJyZXZpYXRlZCkiLAogICAgICAgeT0gIk51bWJlciBvZiBzZW50ZW5jZXMiKQoKCmdncGxvdGx5KGc1KQpgYGAKCklmIHlvdSBob3ZlciBvdmVyIHRoZSBncmFwaCB5b3UgY2FuIGlzb2xhdGUgZWFjaCBzY2hvb2wgaW4gdGhlIGdyYXBoLCBsaWtlIGZhY2V0aW5nLiBXZSBjYW4gc2VlIHRoYXQgdGhlIGxlbmd0aCBvZiB0aGUgdGl0bGUgZG9lc24ndCBkZXBlbmQgb24gZWFjaCBzY2hvb2wuCkZvciBleGFtcGxlLCBzY2hvb2xzIHRoYXQgaGF2ZSBtdWx0aXBsZSB0aXRsZXMgc3VjaCBhcyBgQW5hbHl0aWNgIGFuZCBgZ2VybWFuX2lkZWFsaXNtYCwgdGhlcmUgaXNuJ3QgYSBkaXN0aW5jdCBwYXR0ZXJuIGluIHRoZSBsZW5ndGggb2YgdGl0bGVzIGJ5IHNjaG9vbC4KCgo2LiBIb3cgYWJvdXQgYnkgYXV0aG9yPwoKU2luY2Ugc29tZSBhdXRob3JzIGhhdmUgb25lIHRpdGxlLCBmb3Igc2ltcGxpY2l0eSBsZXRzIGZpbHRlciBmb3IgYXV0aG9ycyB3aXRoIG11bHRpcGxlIHdvcmtzLgpgYGB7ciwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OH0KbXVsdC5hdXRob3JzIDwtIHRpZHlfZGYgJT4lIAogIGZpbHRlcih0eXBlID09ICJuX3RpdGxlIikgJT4lIAogIGZpbHRlcihjb3VudCA+IDEpICU+JSAgCiAgdW5ncm91cCgpICU+JSAKICBkcGx5cjo6c2VsZWN0KGF1dGhvcikgJT4lIHVubGlzdCgpCgpnNiA8LSBkYXRhICU+JSAKICBkcGx5cjo6c2VsZWN0KHNjaG9vbCwgYXV0aG9yLCB0aXRsZSkgJT4lIAogIGZpbHRlcihhdXRob3IgJWluJSBtdWx0LmF1dGhvcnMpICU+JSAKICBnZ3Bsb3QoKSsKICBnZW9tX2JhcihhZXMoZmN0X2luZnJlcSh0aXRsZSksIGZpbGw9YXV0aG9yKSkrCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIGFiYnJldmlhdGUoeCwgbWlubGVuZ3RoID0gNykpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdCA9IDEsIHZqdXN0PTAuNSkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lYW4odGl0bGUucGVyLmF1dGhvciRuX3NlbnQpLCBzaXplPTEsIGNvbD0nZ3JheScpCiAKCmdncGxvdGx5KGc2KQpgYGAKCkFnYWluLCBob3ZlcmluZyBvdmVyIHRoZSBhYm92ZSBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgZXhjZXB0IGZvciBzb21lIGF1dGhvcnMsIHRoZXJlIGlzIG5vIGNsZWFyIHBhdHRlcm4gYXMgdG8gb25lIHdvdWxkIHdyaXRlIHNob3J0IG9yIGxvbmcgd29ya3MuClRoZSBob3Jpem9udGFsIGxpbmUgcmVwcmVzZW50cyB0aGUgbWVhbiBvZiB0aGUgbnVtYmVyIG9mIHNlbnRlbmNlcyBmb3IgYWxsIGF1dGhvcnMuIEJ5IGlzb2xhdGluZyB0aGUgZGF0YSBmb3IgRGVzY2FydGVzLCB3ZSBjYW4gc2VlIHRoYXQgYm90aCBoaXMgd29yayBpbiB0aGUgZGF0YSBzaG93cyB2ZXJ5IGxvdyBudW1iZXIgb2Ygc2VudGVuY2VzLCB3aGVyZWFzIEhlaWRlZ2dlcidzIHdvcmtzIHRlbmQgdG8gYmUgYWJvdmUgYXZlcmFnZS4gQWxzbywgbm90aWNlIHRoYXQgTWFyeCdzIHdvcmsgaXMgb24gYm90aCBlbmRzIG9mIHRoZSBncmFwaC4KCgoKKipJSS4gU2VudGVuY2UgTGVuZ3RoKioKCjEuIExlbmd0aCBvZiBzZW50ZW5jZXMgYW5kIHRva2VucyBieSBzY2hvb2xzLCBhdXRob3JzLCB0aXRsZXMKCioqVG90YWwgc2VudGVuY2UgbGVuZ3RoIHBlciB0aXRsZSoqCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpzZW50Lmxlbi5kZiA8LSBuZXdfZGF0YSAlPiUgCiAgZHBseXI6OnNlbGVjdChzY2hvb2wsIGF1dGhvciwgdGl0bGUsIHNlbnRlbmNlX2xlbmd0aCwgbl90b2tlbnMpICU+JSAKICBncm91cF9ieShzY2hvb2wsIGF1dGhvciwgdGl0bGUpICU+JSAKICBzdW1tYXJpemUoc2VudF9sZW4gPSBzdW0oc2VudGVuY2VfbGVuZ3RoKSwgbl90b2tlbnMgPSBzdW0obl90b2tlbnMpKQoKZGF0YXRhYmxlKHNlbnQubGVuLmRmLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoPTUpKQpgYGAKCioqQXZlcmFnZSBzZW50ZW5jZSBsZW5ndGggcGVyIHRpdGxlKioKYGBge3J9Cmxlbi5hdmcuZGYgPC0gbmV3X2RhdGEgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2Nob29sLCBhdXRob3IsIHRpdGxlLCBzZW50ZW5jZV9sZW5ndGgsIG5fdG9rZW5zKSAlPiUgCiAgZ3JvdXBfYnkoc2Nob29sLCBhdXRob3IsIHRpdGxlKSAlPiUgCiAgc3VtbWFyaXplKHNlbnRfbGVuID0gbWVhbihzZW50ZW5jZV9sZW5ndGgpLCBuX3Rva2VucyA9IG1lYW4obl90b2tlbnMpKQojIG51bWJlciBvZiB3b3JkcyBpbiBhIHNlbnRlbmNlCgpkYXRhdGFibGUobGVuLmF2Zy5kZiwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aD01KSkKYGBgCgoyLiBTZW50ZW5jZSBsZW5ndGggZGlzdHJpYnV0aW9uCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpsZW5ndGhfaW5mbyA8LXN1bW1hcnkoZGF0YSRzZW50ZW5jZV9sZW5ndGgpCmxlbmd0aF9pbmZvCgpnLmxlbiA8LSBuZXdfZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KHNlbnRlbmNlX2xlbmd0aCkgJT4lIAogIGdncGxvdChhZXMobG9nMTAoc2VudGVuY2VfbGVuZ3RoKSkpKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA1MCwgY29sb3I9ImJsYWNrIikrCiAgbGFicyh0aXRsZT0gIlNlbnRlbmNlIGxlbmd0aCBkaXN0cmlidXRpb24iLAogICAgICAgeD0gImxvZzEwKFNlbnRlbmNlIGxlbmd0aCkiLAogICAgICAgeT0gIkZyZXF1ZW5jeSIpCgp0b2tlbl9pbmZvIDwtIHN1bW1hcnkobmV3X2RhdGEkbl90b2tlbnMpCnRva2VuX2luZm8KCmcudG9rZW4gPC0gbmV3X2RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChuX3Rva2VucykgJT4lIAogIGdncGxvdChhZXMobG9nMTAobl90b2tlbnMpKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBjb2xvcj0gImJsYWNrIikrCiAgbGFicyh0aXRsZT0gIk51bWJlciBvZiB0b2tlbnMgZGlzdHJpYnV0aW9uIiwKICAgICAgIHg9ICJsb2cxMChOdW1iZXIgb2YgdG9rZW5zKSIsCiAgICAgICB5PSAiRnJlcXVlbmN5IikKCnBhcihtZnJvdz0gYygxLCAyKSkKZy5sZW4gOyBnLnRva2VuCmBgYAoKRm9yIHdoaWNoIHNlbnRlbmNlIGhhcyAwIHRva2Vucz8KYGBge3J9CmlkIDwtIHdoaWNoKG5ld19kYXRhJG5fdG9rZW5zID09IDApCm5ld19kYXRhW2lkLGMoInNlbnRlbmNlX3N0ciIsICJ0b2tlbml6ZWRfdHh0IildCgoKI2ZpbHRlciBvdXQgZm9yIHJvd3MgdGhhdCBob2xkcyBzZW50ZW5jZXMgd2l0aG91dCBtZWFuaW5nCm5ld19kYXRhIDwtIG5ld19kYXRhICU+JSAKICBmaWx0ZXIobl90b2tlbnMgPjApCgpzdW1tYXJ5KG5ld19kYXRhJG5fdG9rZW5zKQpgYGAKCgoKMi4gSXMgdGhlcmUgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG51bWJlciBvZiBzZW50ZW5jZXMgYW5kIG51bWJlciBvZiB3b3JkcyBpbiBhIHNlbnRlbmNlIGJ5IHRpdGxlPwpGb3IgZXhhbXBsZSwgZGlkIHdyaXRpbmdzIGNvbnNpc3Qgb2YgbWFueSBzaG9ydCBzZW50ZW5jZXMgb3IgZmV3IGxlbmd0aHkgc2VudGVuY2VzPwoKYGBge3J9CmNvcnJfZGYgPC0gdGl0bGUucGVyLnNjaG9vbCAlPiUgCiAgbGVmdF9qb2luKHNlbnQubGVuLmRmLCBieSA9IGMoInNjaG9vbCIsICJhdXRob3IiLCAidGl0bGUiKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZHBseXI6OnNlbGVjdCh0aXRsZSwgbl9zZW50LCBuX3Rva2VucykKCmcuY29yIDwtIGdncGxvdChjb3JyX2RmKSsKICBnZW9tX3BvaW50KGFlcyhsb2cxMChuX3NlbnQpLCBsb2cxMChuX3Rva2VucykpKQoKZy5jb3IKYGBgCgpUaGUgc2NhdHRlciBwbG90IHNlZW1zIHRvIHNob3cgc29tZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSAyIHZhcmlhYmxlcy4KClN0YXRpc3RpY2FsbHksCmBgYHtyfQpzaGFwaXJvLnRlc3QoY29ycl9kZiRuX3NlbnQpCnNoYXBpcm8udGVzdChjb3JyX2RmJG5fdG9rZW5zKQpgYGAKCldlIGNhbm5vdCBjb21wdXRlIHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlc2UgMiB2YXJpYWJsZXMgc2luY2UgaXQgZG9lcyBub3QgcGFzcyB0aGUgU2hhcGlyby1XaWxrIHRlc3Qgb2Ygbm9ybWFsaXR5LgpJbnN0ZWFkLCB3ZSBjb21wdXRlIHRoZSBLZW5kYWxsIGNvcnJlbGF0aW9uIHRoYXQgY29tcHV0ZXMgY29ycmVsYXRpb24gYnkgdGhlICJyYW5rIi4KYGBge3J9CnJlc3VsdCA8LSBjb3IudGVzdChjb3JyX2RmJG5fc2VudCwgY29ycl9kZiRuX3Rva2VucywgbWV0aG9kID0gImtlbmRhbGwiKQpyZXN1bHQKYGBgCgpBbHRob3VnaCB3ZSBjYW5ub3QgY29uY2x1c2l2ZWx5IHNheSB0aGF0IHRoZSBsb25nZXIgdGhlIHNlbnRlbmNlcywgdGhlIGxvbmdlciB0aGUgd29yayBhcyB0aGF0IHdvdWxkIGJlIHRvbyBtdWNoIG9mIGEgc3RyZXRjaCwgd2Ugc3RpbGwgY2FuIHNheSB0aGF0IHRoZSB3b3JrcyBhcmUgbm90IGNvbnNpc3RlZCBvZiBleGNlc3NpdmVseSBtdWNoIHNob3J0IHNlbnRlbmNlcyBvciBsZXNzIGxlbmd0aHkgc2VudGVuY2VzLgoKCgoKIyMgV29yZCBDbG91ZAoKTWFueSBhbmFseXNpcyBoYXMgYmVlbiBkb25lIG9uIGhvdyBtYW55IGRpc3RpbmN0IHdvcmRzIHdlcmUgdXNlZCBieSBhdXRob3JzLCBvciB3aGF0IHdvcmRzIHdlcmUgbW9zdGx5IHVzZWQgYnkgdGhlbS4KSW5zdGVhZCwgSSB0cmllZCB0byBsb29rIGF0IGF1dGhvcnMgd2hvIGhhZCBtb3JlIHRoYW4gb25lIHRpdGxlIGluIHRoaXMgZGF0YSB0byBzZWUgaWYgdGhlaXIgdXNlIG9mIHdvcmRzIGhhcyBjaGFuZ2VkIG92ZXIgdGltZS4KTGV0J3MgdGFrZSBhIGZldyBhdXRob3JzIGZyb20gdGhlIGxpc3Q6IE5pZXR6c2NoZSwgSGVnZWwsIGFuZCBLYW50CmBgYHtyLHdhcm5pbmc9IEZBTFNFfQptdWx0LmF1dGhvcnMKCm1sdF9wdWIgPC0gZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KGF1dGhvciwgdGl0bGUsIG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUsIHRva2VuaXplZF90eHQpICU+JSAKICBmaWx0ZXIoYXV0aG9yICVpbiUgbXVsdC5hdXRob3JzKQoKIyBjcmVhdGUgZGF0YWZyYW1lIGZvciBlYWNoIGF1dGhvcgpuaWV0IDwtIG1sdF9wdWIgJT4lIGZpbHRlcihhdXRob3IgPT0gIk5pZXR6c2NoZSIpCmhlZ2VsIDwtIG1sdF9wdWIgJT4lIGZpbHRlcihhdXRob3IgPT0gIkhlZ2VsIikKa2FudCA8LSBtbHRfcHViICU+JSBmaWx0ZXIoYXV0aG9yID09ICJLYW50IikKYGBgCmBgYHtyIHdhcm5pbmc9RkFMU0V9Cm5pZXQgJT4lIHNlbGVjdCh0aXRsZSwgb3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSkgJT4lIAogIGRpc3RpbmN0KHRpdGxlLCAua2VlcF9hbGw9VFJVRSkgJT4lIGFycmFuZ2Uob3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSkKICAKbmlldF90eHQxIDwtIG5pZXQgJT4lIGZpbHRlcihvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlPT0xODg2KQpuaWV0X3R4dDIgPC0gbmlldCAlPiUgZmlsdGVyKG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGU9PTE4ODcpCm5pZXRfdHh0MyA8LSBuaWV0ICU+JSBmaWx0ZXIob3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZT09MTg4OCkKCnBhcihtZnJvdz0gYygxLCAzKSkKY3JlYXRlX3djKG5pZXRfdHh0MSk7IGNyZWF0ZV93YyhuaWV0X3R4dDIpOyBjcmVhdGVfd2MobmlldF90eHQzKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmhlZ2VsICU+JSBzZWxlY3QodGl0bGUsIG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUpICU+JSAKICBkaXN0aW5jdCh0aXRsZSwgLmtlZXBfYWxsPVRSVUUpICU+JSBhcnJhbmdlKG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUpCiAgCmhlZ2VsX3R4dDEgPC0gaGVnZWwgJT4lIGZpbHRlcihvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlPT0xODA3KQpoZWdlbF90eHQyIDwtIGhlZ2VsICU+JSBmaWx0ZXIob3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZT09MTgxNykKaGVnZWxfdHh0MyA8LSBoZWdlbCAlPiUgZmlsdGVyKG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGU9PTE4MjApCgpwYXIobWZyb3c9IGMoMSwgMykpCmNyZWF0ZV93YyhoZWdlbF90eHQxKTsgY3JlYXRlX3djKGhlZ2VsX3R4dDIpOyBjcmVhdGVfd2MoaGVnZWxfdHh0MykKCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRX0Ka2FudCAlPiUgc2VsZWN0KHRpdGxlLCBvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKSAlPiUgCiAgZGlzdGluY3QodGl0bGUsIC5rZWVwX2FsbD1UUlVFKSAlPiUgYXJyYW5nZShvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKQogIAprYW50X3R4dDEgPC0ga2FudCAlPiUgZmlsdGVyKG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGU9PTE3ODEpCmthbnRfdHh0MiA8LSBrYW50ICU+JSBmaWx0ZXIob3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZT09MTc4OCkKa2FudF90eHQzIDwtIGthbnQgJT4lIGZpbHRlcihvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlPT0xNzkwKQoKcGFyKG1mcm93PSBjKDEsIDMpKQpjcmVhdGVfd2Moa2FudF90eHQxKTsgY3JlYXRlX3djKGthbnRfdHh0Mik7IGNyZWF0ZV93YyhrYW50X3R4dDMpCmBgYAoKCiMjIyBGaW5kaW5ncwpXZSBzZWUgYm90aCBjaGFuZ2VzIGFuZCBub25jaGFuZ2VzLgoKMS4gRm9yIE5pZXR6c2NoZSwgZm9yIGFsbCB0aHJlZSB5ZWFycyB0aGUgbW9zdCB1c2VkIHdvcmQgaXMgYWxsIHNpbWlsYXJseSAib25lIiwgYW5kICJ3aWxsIi4gSG93ZXZlciwgd2UgY2FuIHNlZSBhIHNoaWZ0IGluIHN1YmplY3QuIEludGhlIGVhcmx5IHB1YmxpY2F0aW9uLCBoZSBmb2N1c2VzIG1vcmUgb24gbWFuLCBtb3JhbGl0eSwgZ29vZCwgZXRjLiBIb3dldmVyIHRoZSBsYXN0IHdvcmxkIGNsb3VkIHNob3dzIG1vcmUgb2YgZ29kLCB3b3JsZCwgd2hvbGUsIHBlb3BsZSwgYW5kIGV0Yy4KMi4gRm9yIEhhZ2VsLCBoZSBzdGFydGVkIG91dCB3aXRoIHdvcmRzIHN1Y2ggYXMgc3ByaXQsIHB1cmVtIHVuaXZlcnNhbC4gTGF0ZXIsIGhlIGhhcyBzaGlmdGVkIHRvIG1vcmUgb2QgZGV0ZXJtaW5hdG9pbiwgcmlnaHQsIHNlbGYsIGFuZCBjb25zY2lvdXNuZXNzIHJhdGhlciB0aGFuIHNwaXJpdHVhbC4KMy4gRm9yIEthbnQsIGhlIGNvbnN0YW50bHkgdXNlcyB0aGUgd29yZHMgcmVhc29uICwgbGF3LCBqdWRnbWVudCwgZW1waXJpY2FsLCBldGMuIEZyb20gaGlzIGNob2ljZSBvZiB3b3Jkcywgd2UgY2FuIHNlZSB0aGF0IGhpcyBzdWJqZWN0cyBhcmUgZGlzdGluY3QgZnJvbSB0aGUgcHJldmlvdXMgMiBwaGlsb3NvcGhlcnMu